#include "assert.h"
#include "cstdio"
#include "cstring"
#include "airgap.h"
#include "tfparser.h"
#include "boundary.h"
#include "store.h"

#define COMMANDS_NUM	(11)

TextFileParser* tf;

typedef struct {
	char command[COMMAND_MAX_LEN];
	int (*processing)(FILE* dev, const char* command);
} ParseData_t;

int create_layer(FILE* dev, const char* command)
{
	double Width = tf->GetNextDouble();
	assert(Width > 0);
	int Cells = tf->GetNextInt();
	assert(Cells > 0);
	int mid = tf->GetNextInt();
	assert((mid >= 0) && (mid<MATERIALS_MAX_NUM));
	
	thm->add(Cells, Width, materials[mid], 0.);
	return 0;
}
int create_material(FILE* dev, const char* command)
{
	int mid = tf->GetNextInt();
	assert((mid >= 0) && (mid<MATERIALS_MAX_NUM));
	string mname;
	int res = tf->GetNextString(&mname);
	assert(res == 0);
	double L = tf->GetNextDouble();
	assert(L > 0);
	double RHO = tf->GetNextDouble();
	assert(RHO > 0);
	double CP = tf->GetNextDouble();
	assert(CP > 0);
	double EPS = tf->GetNextDouble();
	assert(EPS >= 0);
	double Tdestr = tf->GetNextDouble();
	assert(Tdestr >= 0);
	double A = tf->GetNextDouble();
	assert(A >= 0);
	double B = tf->GetNextDouble();
	assert(B >= 0);
	int Type = tf->GetNextInt();
	assert(Type >= 0);	
	materials[mid] = new ConstMaterial(mname.c_str(), stdout, L, RHO, CP, EPS, Tdestr, A, B, Type);
	return 0;
}
int create_DBMaterial(FILE* dev, const char* command)
{
	int mdb_id = tf->GetNextInt();
	assert(mdb_id >= 0);
	int mid = tf->GetNextInt();
	assert((mid >= 0) && (mid<MATERIALS_MAX_NUM));
	materials[mid] = new DBMaterial(mdb_id, "Materials.sqlite", stdout);
	return 0;
}
int create_FLBC(FILE* dev, const char* command)
{
	double Tw = tf->GetNextDouble();
	assert(Tw >= 0.);
	thm->setLBC(new CFOBoundary(Tw));
	return 0;
}
int create_FRBC(FILE* dev, const char* command)
{
	double Tw = tf->GetNextDouble();
	assert(Tw >= 0.);
	thm->setRBC(new CFOBoundary(Tw));
	return 0;
}
int create_SLBC(FILE* dev, const char* command)
{
	double ACP = tf->GetNextDouble();
	double IE = tf->GetNextDouble();
	assert(IE > 0.);
	double q = tf->GetNextDouble();
	double eps = tf->GetNextDouble();
	thm->setLBC(new CSOBoundary(ACP, IE, q, eps));
	return 0;
}
int create_SRBC(FILE* dev, const char* command)
{
	double ACP = tf->GetNextDouble();
	double IE = tf->GetNextDouble();
	assert(IE > 0.);
	double q = tf->GetNextDouble();
	double eps = tf->GetNextDouble();
	thm->setRBC(new CSOBoundary(ACP, IE, q, eps));
	return 0;
}
int solve(FILE* dev, const char* command)
{
	double time = tf->GetNextDouble();
	assert(time > 0.);
	double initial_timestep = tf->GetNextDouble();
	solver->Solve(time, initial_timestep);
	return 0;
}
int set_uniform_temp(FILE* dev, const char* command)
{
	double T0 = tf->GetNextDouble();
	assert(T0 >= 0.);
	func_points_t Tf;
	double T[1] = {T0};
	double x[1] = {0};
	Tf.count = 1;
	Tf.x = x;
	Tf.y = T;
	thm->setTemperature(&Tf);
	return 0;
}
int set_prefs(FILE* dev, const char* command)
{
	double TIMESTEP_MIN = tf->GetNextDouble();
	assert(TIMESTEP_MIN > 0.);
	double TIMESTEP_MAX = tf->GetNextDouble();
	assert(TIMESTEP_MAX > 0.);
	double DT_MAX = tf->GetNextDouble();
	assert(DT_MAX >= 0.);
	solver->setPrefs(TIMESTEP_MIN, TIMESTEP_MAX, DT_MAX);
	return 0;
}
int create_airgap(FILE* dev, const char* command)
{
	double width = tf->GetNextDouble();
	assert(width > 0.);
	int PointNum = thm->lcnum+1;
	thm->add(1, width, new CAirGap(thm, PointNum), 0.);
	return 0;
}
ParseData_t ParseData[COMMANDS_NUM] = {	{"LAYER", create_layer},
					{"CM", create_material},
					{"DM", create_DBMaterial},
					{"FLBC", create_FLBC},
					{"FRBC", create_FRBC},
					{"SLBC", create_SLBC},
					{"SRBC", create_SRBC},
					{"SOLVE", solve},
					{"SET_UNIFORM_TEMP", set_uniform_temp},
					{"SOLVER_PREFS", set_prefs},
					{"AIRGAP", create_airgap}
					};

static void usage(char* argv[])
{
	printf("USAGE: %s <SOURCE FILE NAME>\n", argv[0]);
}
int main(int argc, char* argv[])
{
	FILE* fin = 0;
	int i;
	char* comm;
	
	if (argc != 2) {
		return 1;
		usage(argv);
	}
	fin = fopen(argv[1], "rt");
	assert(fin != 0);
	tf = new TextFileParser(fin);
	thm = new thm_t();
	solver = new CTHSolver(thm);
	while (!feof(fin)) {
		comm = tf->GetNextCommand();
		if (comm == 0)
			break;
		i=0;
		while ((strcmp(ParseData[i].command, comm) != 0) && (i < COMMANDS_NUM)) i++;
		if (i == COMMANDS_NUM) {
			printf("I DON'T NOTHING COMMAND: %s. Exit.\n", comm);
			return -1;
		} else
			ParseData[i].processing(fin, comm);
	}
	fclose(fin);
	thm->print();
	return 0;
}
